#include "Vector2.h"

Vector2::Vector2()
{
	this->_x = 0.0;
	this->_y = 0.0;
	this->_w = 1.0;
}

Vector2::Vector2( const Vector2& vec )
{
	this->_x = vec.getX();
	this->_y = vec.getY();
	this->_w = vec.getW();
}

Vector2::Vector2( float x, float y)
{
	this->_x = x;
	this->_y = y;
	this->_w = 1.0;
}

Vector2::Vector2( float x, float y, float w )
{
	this->_x = x;
	this->_y = y;
	this->_w = w;
}

//Getter/Setter
float Vector2::getX() const
{
	return this->_x;
}
float Vector2::getY() const
{
	return this->_y;
}
float Vector2::getW() const
{
	return this->_w;
}
void Vector2::setX(float x)
{
	this->_x = x;
}
void Vector2::setY(float y)
{
	this->_y = y;
}
void Vector2::setW(float w)
{
	this->_w = w;
}

float Vector2::getAbsolute() const
{
	return sqrt(this->_x*this->_x + this->_y*this->_y);
}

float Vector2::getSquare() const
{
	return (_x*_x) + (_y*_y);
}

void Vector2::setLength( float length )
{
	float len = this->_x*this->_x + this->_y*this->_y;
	if(length >= 0.0 && fabs(len - length * length) < (GeoMath::EPS * GeoMath::EPS))
	return;

	if(len <= (GeoMath::EPS * GeoMath::EPS))
		return;

	float val = length;
	val = val / sqrt(len);
	this->_x *= val;
	this->_y *= val;
}

float Vector2::getAngle( const Vector2& vec2) const
{
	return acos( ( (*this)*vec2 ) / ( this->getAbsolute() * vec2.getAbsolute() ) );
}



Vector2 Vector2::operator + (const Vector2& vec2) const
{
	Vector2 vec(this->_x + vec2._x,this->_y + vec2._y);
	return vec;
}

void Vector2::operator += (const Vector2& vec2)
{
	this->_x += vec2.getX();
	this->_y += vec2.getY();
}

Vector2 Vector2::operator - (const Vector2& vec2) const
{
	Vector2 vec(this->_x - vec2._x,this->_y - vec2._y);
	return vec;
}

void Vector2::operator -= (const Vector2& vec2)
{
	this->_x -= vec2.getX();
	this->_y -= vec2.getY();
}

float Vector2::operator * (const Vector2& vec2) const
{
	return this->_x * vec2._x + this->_y * vec2._y;
}	

Vector2 Vector2::operator * (float scalar) const
{
	Vector2 tmp( this->_x * scalar, this->_y * scalar  );
	return tmp;
};	

void Vector2::operator *= (float scalar)
{
	this->_x *= scalar;
	this->_y *= scalar;
}

Vector2 Vector2::operator / (float scalar) const
{
	Vector2 null;
	if( fabs(scalar) < GeoMath::EPS )
		 return null;
	Vector2 tmp( this->_x / scalar, this->_y / scalar );
	return tmp;
};	

void Vector2::operator /= (float scalar)
{
	if( fabs(scalar) < GeoMath::EPS )
	 return;
	this->_x /= scalar;
	this->_y /= scalar;
}

bool Vector2::isNullVector() const
{
	return ( ( fabs( _x ) < GeoMath::EPS ) && ( fabs( _y ) < GeoMath::EPS ) );
}

Vector2 Vector2::getNormal() const
{
	if( isNullVector() )
		return *this;

	float abs = getAbsolute();
	Vector2 tmp( _x / abs, _y / abs );

	return tmp;
}

void Vector2::normalize()
{
	if( isNullVector() )
		return;

	float abs = getAbsolute();
	_x /= abs;
	_y /= abs;	
}

float Vector2::componentsSum() const
{
	return _x + _y;
}


Vector2 Vector2::projectionOn( const Vector2& vec2 ) const
{
	if( vec2.isNullVector() )
		return Vector2();
	
	return vec2 * ( ( (*this) * vec2) /  vec2.getSquare() );	
}



ostream & operator<< (ostream &o, const Vector2 &vec)
{
	o << "(" << vec.getX() << "," << vec.getY() << ",:" << vec.getW() << ":)";
	return o;
}


